<?php
namespace app\common\service;

use app\common\model\FilmModel;
use Elasticsearch\ClientBuilder;

/**
 * 搜索处理
 */
class EsSearchService
{
    const INDEX_NAME = 'btfilm';

    /**
     *
     * @var \Elasticsearch\Client
     */
    private $client;


    static $sortModel = array(
        // 按相关度降序排列（最好的匹配排在最前面）
        1 => [
            [
                [ '_score' => ['order' => 'desc'] ],
                [ 'c_time' => ['order' => 'desc'] ],
            ],
            '相关度',
            2,
        ],
        // 按相关度升序排列
        2 => [
            [
                [ '_score' => ['order' => 'asc'] ],
                [ 'c_time' => ['order' => 'desc'] ],
            ],
            '相关度',
            1,
        ],
        // 按时间降序排列
        3 => [
            [
                [ 'c_time' => ['order' => 'desc'] ],
                [ '_score' => ['order' => 'desc'] ],
            ],
            '时间',
            4,
        ],
        // 按时间升序排列
        4 => [
            [
                [ 'c_time' => ['order' => 'asc'] ],
                [ '_score' => ['order' => 'desc'] ],
            ],
            '时间',
            3
        ],
    );

    static $instance = null;


    public function __construct()
    {
        $hosts = config('elasticsearch.' . self::INDEX_NAME . '.host');
        $this->client = ClientBuilder::create()->setHosts($hosts)->build();
    }

    /**
     * @return EsSearchService
     */
    public static function getInstance() {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }


    public function buildIndex($film) {
        $content = strip_tags($film['content']);
        $content = preg_replace("/\r|\n|\s{2,}/", '', $content);

        $index['index'] = self::INDEX_NAME; //索引名称
        $index['id'] = $film['id'];
        $index['type'] = '_doc';
        $index['body'] = [
            'id'      => $film['id'],
            'title'   => $film['title'],
            'content' => $content,
            'status'  => $film['status'],
            'c_time'  => $film['c_time'],
            'site_id' => $film['site_id'],
        ];
        $res = $this->client->index($index);
        return $res;
    }

    public function buildIndexOne($film) {
        $res = $this->client->index($film);
        return $res;
    }

    /**
     * 初始化sphinx客户端
     */
    public function search($keyword, $page, $pagesize, $sort = 1)
    {
        $page = $page ? $page : 1;
        $offset = ($page - 1) * $pagesize;

        if(isset(self::$sortModel[$sort])){
            $sort = self::$sortModel[$sort][0];
        } else {
            $sort = self::$sortModel[$sort][0];
        }

        $index['index'] = self::INDEX_NAME;
        if (!empty($keyword)) {
            $index['body'] = [
                'query' => [
                    'multi_match' => [
                        'query' => $keyword,
                        'fields' => ['title^5', 'content'],
                        'fuzziness' => 'AUTO',
                    ]
                ],
                'from' => $offset,
                'size' => $pagesize,
                'highlight' => [
                    'fields' => [
                        'title' => new \StdClass(),
                        'content' => new \StdClass(),
                    ]
                ]
            ];
        }

        $index['body']['sort'] = $sort;
        $index['body']['from'] = $offset;
        $index['body']['size'] = $pagesize;

        $res = $this->client->search($index);
        if (empty($res) || empty($res['hits'])) {
            return [
                'films' => [],
                'total' => 0,
            ];
        }

        $total = $res['hits']['total']['value'];
        $films = [];
        foreach ($res['hits']['hits'] as $hit) {
            $film = $this->formatFilm($hit);
            if ($film === false) {
                continue;
            }
            $films[] = $film;
        }

        return [
            'films' => $films,
            'total' => $total,
        ];
    }


    private function formatFilm($hit) {
        $film = FilmModel::get($hit['_id']);
        if (empty($film)) {
            return false;
        }

        if (empty($hit['highlight']['content'])) {
            $content = mb_substr(strip_tags($film->content), 0, 300);
            $content = preg_replace("/\s{2,}|]/", '', $content);
        } else {
            $content = $this->formatFilmContent($hit['highlight']['content']);
        }

        $film->score = $hit['_score'];
        $film->highlight_title = empty($hit['highlight']['title']) ? $film->title : array_shift($hit['highlight']['title']);
        $film->content = $content;
        return $film;
    }


    private function formatFilmContent($contents) {
        $content = array_shift($contents);
        if (!empty($contents)) {
            $content .= array_shift($contents);
        }
        return $content;
    }
}
